from core.worker import Worker
from core.plane import Plane
from collections import deque
from collections import namedtuple,defaultdict
import simpy
import math
import numpy as np

class Board(object):
    '''
     甲板类 ：
        甲板保障过程的主要逻辑功能

    '''

    def __init__(self):
        # 飞机 维护组工作人员
        self.workers = []
        self.planes = []
        self.__ready_tasks = deque()
        self.__un_ready_tasks = list()

        self.__worker_pos = None
        self.__group = None
        self.num_group = None


    def reset(self,env:simpy.Environment):

        for worker in self.workers:
            worker.reset()

        for plane in self.planes:
            plane.reset(env)

        self.__ready_tasks.clear()
        self.__un_ready_tasks.clear()

        for plane in self.planes:
            self.__ready_tasks.extend(plane.ready_unstarted_tasks)
            self.__un_ready_tasks.extend(plane.unreleased_tasks)


    @property
    def ready_tasks(self):
        ls = []
        for plane in self.planes:
            ls.extend(plane.ready_unstarted_tasks)
        return ls

    @property
    def finished_planes(self):
        ls = []
        for plane in self.planes:
            if plane.finished:
                ls.append(plane)
        return ls


    @property
    def has_task(self):
        return  len(self.__ready_tasks) != 0 \
                or len(self.__un_ready_tasks) != 0

    def next_task(self):

        task = None
        # 将释放的task放入自由队列
        if len(self.__ready_tasks)==0 and \
                len(self.__un_ready_tasks) != 0:
            redeay_task = []
            for i in range(len(self.__un_ready_tasks)):
                if self.__un_ready_tasks[i].ready:
                    redeay_task.append(self.__un_ready_tasks[i])
            if len(redeay_task) != 0 :
                # self.__un_ready_tasks.pop()
                self.__ready_tasks.extend(redeay_task)
                [self.__un_ready_tasks.remove(x) for x in redeay_task]

        if len(self.__ready_tasks) != 0:

            task =self.__ready_tasks.popleft()

        return task

    def insert_task(self,task):
        '''如果baclog已满，需要返回到队列中'''

        self.__ready_tasks.appendleft(task)

    def allocate_task(self, group, alloc_task):

        # for worker in self.workers:
        #     if worker.accommodate(alloc_task):
        #         # worker.run_task() # 运行任务。。。
        #         return True
        # return False
        workertype_dict = {'kp1': 0, 'kp2': 1, 'kp3': 2, 'kp4': 3}
        worker_pos = group*4 + workertype_dict[alloc_task.worker_type]
        if worker_pos not in self.__group[group]:
            return False
        worker = self.__worker_pos[worker_pos]
        if worker.accommodate(alloc_task):
            return True
        return False

    def pre_allocate(self,group,slot):

        workertype_dict = {'kp1': 0, 'kp2': 1, 'kp3': 2, 'kp4': 3}
        worker_pos = group * 4 + workertype_dict[slot.worker_type]
        if worker_pos  in self.__group[group]:
            return True
        return False

    def canMoveOn(self):

        return any(w.has_unfinish_tasks for w in self.workers)

    def add_workers(self, worker_configs):

        # for worker_config in worker_configs:


        workertype_dict = {'kp1': 0, 'kp2': 1, 'kp3': 2, 'kp4': 3}
        workertype_pos = {'kp1': -1, 'kp2': -1, 'kp3': -1, 'kp4': -1}

        worker_pos = defaultdict(Worker)

        for worker_config in worker_configs:
            # append workers
            worker = Worker(worker_config)
            self.workers.append(worker)
            worker.attach(self)
            # define position for workers with

            worker_type = worker_config.worker_type
            if workertype_pos[worker_type] == -1:
                pos = workertype_dict[worker_type]
                worker_pos[pos] = worker
                workertype_pos[worker_type] = pos
            else:
                workertype_pos[worker_type] += 4
                pos = workertype_pos[worker_type]
                worker_pos[pos] = worker
        # print("========")
        # print(worker_pos)
        # print(worker_pos.keys())
        group = defaultdict(list)
        num_group = math.ceil((max(worker_pos.keys())+1) / 4)
        pos_list = list(worker_pos.keys())

        for num in range(num_group):
            num_re = 4*num
            group[num] = [pos for pos in pos_list if pos in [num_re,num_re+1,num_re+2,num_re+3]]

        self.__worker_pos = worker_pos
        self.__group = group
        self.num_group = num_group
        # self.type_group = group_type


    @property
    def get_workers_id(self):
        workers_id = []
        for worker in self.workers:
            workers_id.append(worker.id)

        workers_id.sort()

        return workers_id

    def add_plane(self, plane):
        self.planes.append(plane)
        self.__ready_tasks.extend(plane.ready_unstarted_tasks)
        self.__un_ready_tasks.extend(plane.unreleased_tasks)

    @property
    def all_planes_finished(self) -> bool:
        for plane in self.planes:
            if not plane.finished:
                return False
        return True

    @property
    def state(self):
        # todo: 表征甲板的状态
        # horizen, group*4
        worker_state = np.zeros((Worker.time_horizon, self.num_group * 4), dtype=np.float32)

        all_pos = set(range(0, self.num_group * 4))
        invalid_pos = all_pos - set(self.__worker_pos.keys())
        # 给无效状态的全部填充-1
        for pos in invalid_pos:
            worker_state[:, pos] = -1

        for pos, worker in self.__worker_pos.items():
            if worker.duration > 0:
                try:
                    worker_state[:worker.duration, pos] = 1
                except TypeError:

                    print("eoor in board.file",worker.duration,pos)

        return worker_state

    @property
    def left_time(self):
        # 剩余时间task的剩余时间
        duration = 0
        for task in self.__un_ready_tasks:
            duration += task.duration

        for task in self.__ready_tasks:
            duration +=task.duration

        #worker _left_time

        for worker in self.workers:
            duration += worker.duration

        return duration

    @property
    def task_state(self):
        '''将每个plane的info对应到当前的task graph'''
        workertype_dict = {'kp1': 0, 'kp2': 1, 'kp3': 2, 'kp4': 3}
        #
        # task_state = np.zeros((4, 4), dtype=np.float32)
        un_task_state = np.zeros((len(self.planes), 16), dtype=np.float32)
        #

        # for task in self.__un_ready_tasks:
        #     un_task_state[0,workertype_dict[task.worker_type]] += task.duration
        i = 0
        plane_id = dict()
        for plane in self.planes:
            # info为unready task graph for plane
            plane_info = plane.unready_layer_taskInfo()
            # for layer in range(1,4):
            plane_id[plane.id] = i
            un_task_state[i, :] = plane_info
            i += 1

        for task in self.__ready_tasks:
            index = plane_id[task.plane.id]
            un_task_state[index, workertype_dict[task.worker_type]] += task.duration / 12

        return un_task_state



